package com.spzx.common.rabbit.config;

import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;

/**
 * 实现ApplicationListener<ApplicationReadyEvent> 接口并重写onApplicationEvent方法后，
 * 我们可以在Spring容器完成所有Bean的初始化和配置之后
 * 执行onApplicationEvent内的方法
 */
@Slf4j
@Component
public class RabbitInitConfigApplicationListener implements ApplicationListener<ApplicationReadyEvent> {

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Override
    public void onApplicationEvent(ApplicationReadyEvent event) {
        this.setupCallbacks();
    }

    private void setupCallbacks() {
        /**
         * 为当前的rabbitTemplate设置生产者Confirm确认机制
         * Confirm确认机制能够保证消息是否正确的从{生产者}发送到{交换机}
         * 当消息到交换器成功，则ack=true，否则ack=false
         * 我们可以通过回调函数来确认消息是否发送成功
         */
        this.rabbitTemplate.setConfirmCallback((correlationData, ack, cause) -> {
            if (ack) {
                //消息到交换器成功
                log.info("消息发送到Exchange成功：{}", correlationData);
            } else {
                //消息到交换器失败
                log.error("消息发送到Exchange失败：{}", cause);
            }
        });
        /**
         * 为当前的rabbitTemplate设置生产者Return退回机制
         * 如果当前消息从{交换机}发送到{队列}的过程中  失败了
         * 那么就会触发Return退回机制，触发回调函数
         */
        this.rabbitTemplate.setReturnsCallback(returnedMessage -> {
            log.error("消息从交换机发送到队列中发生错误: " + returnedMessage.getMessage()
                    + "\n 响应码: " + returnedMessage.getReplyCode()
                    + "\n 响应消息: " + returnedMessage.getReplyText()
                    + "\n 交换机: " + returnedMessage.getExchange()
                    + "\n 路由: " + returnedMessage.getRoutingKey());
        });

    }
}